<?php
Yii::import('Core.extensions.web.helpers.FDom');
class PageService extends FServiceBase
{
    public function init() {
        $criteria = new CDbCriteria;
        $criteria->compare('site_id', Yii::app()->cmsManager->site['id']);
        $this->attachBehavior('nested', array(
            'class'=>'application.modules.Cms.services.NestedBehavior',
            'className'=>'Page',
            'attributeStatus'=>'status',
            'criteria'=>$criteria,
        ));
    }

    /**
    * Get a Page model given its ID
    * 
    * @param int id Page ID
    * @return FServiceModel
    */
    public function get($params){
        $model = Page::model()->findByPk($this->getParam($params, 'id', 0));
        if (! $model)
            $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page','Invalid ID.'));
        $this->result->processed('model', $model);
        return $this->result;
    }

    public function saveDetails($params) {
        /**
        * @var CModel
        */
        $model = $this->getModel($params['Page'],'Page');
        $this->result->processed('model', $model);

        $newRecord = false;
        if ($model->id <= 0)
        {
            $model->status = 1;
            $model->revision_id = 1;
            $this->result->processed('newModel', 1);
            $newRecord = true;
        }
        else
            $this->result->processed('newModel', 0);

        $attributes = $model->attributes;
        if ($model->type !== Page::TYPE_STANDARD)
        {
            unset($attributes['route']);
            unset($attributes['view']);
        }
        $attributes = array_keys($attributes);

        if (!$model->validate($attributes))
            $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page', 'Submitted data is missing or invalid.'));
        elseif ($this->getParam($params, 'validateOnly',0) == TRUE)
            return $this->result;
        elseif (!$model->save(false, $attributes))
            $this->result->fail(ERROR_HANDLING_DB, Yii::t('CmsModule.Page','Error while saving submitted data into database.'));

        if ($model->hasErrors() == false) {
            $this->result->processed('model', $model);
            //If new record created or template revision required
            if ($newRecord || $params['PageRevision']['template_content_id']!='' )
            {
                FSM::_run('Cms.PageRevision.save',array(
                'PageRevision'=>array(
                'id'=>1,
                'page_id'=>$model->id,
                'created_by'=>Yii::app()->user->id,
                'updated_by'=>Yii::app()->user->id,
                'creation_datetime'=>date('Y-m-d H:i:s'),
                'last_update'=>date('Y-m-d H:i:s'),
                'log'=>'Init',
                'template_content_id'=>$params['PageRevision']['template_content_id'],
                'css_files'=>$params['PageRevision']['css_files'],
                'js_files'=>$params['PageRevision']['js_files'],
                ),
                'type'=>$model->type,
                ));
                FSM::run('Cms.Page.initCurrentByPage', array('id'=>$model->id,'site_id'=>$model->site_id));
                //add required widgets
                //FSM::run('Cms.PageWidget.addRequiredWidget', array('page_id'=>$model->id));
            }
            
            //parse and create site urls when page type is not Type group
            if($model->type!=Page::TYPE_GROUP){
                if (isset($params['PageUrl']) && is_array($params['PageUrl']) && count($params['PageUrl']) && empty($params['PageUrl'][0]['url']) === false) {
                    $params['page_id'] = $model->id;
                    $this->saveUrls($params);
                    FSM::run('Cms.pageUrl.updateCacheUrlBySite',array('site_id' => $model->site_id));
                }
                elseif ($newRecord)
                {
                    $result = FSM::run('Cms.PageUrl.save', array('PageUrl'=>array(
                    'page_id'=>$model->id,
                    'url'=>$model->alias,
                    'status'=>PageUrl::STATUS_ACTIVE,
                    'default'=>true,
                    )))->model;
                    if ($result->hasErrors()) {
                        Yii::log(CVarDumper::dumpAsString($result->getErrors()), CLogger::LEVEL_ERROR);
                    } else {
                        FSM::run('Cms.pageUrl.updateCacheUrlBySite',array('site_id' => $model->site_id));
                    }
                }
                else
                    $this->result->processed('pageUrls', array());
            }
            if ($model->type == Page::TYPE_STANDARD)
            {
                FSM::run('Cms.pageUrl.updateCacheUrlBySite',array('site_id' => $model->site_id));
            }
        }

        return $this->result;
    }

    protected function saveUrls($params)
    {
        $pageUrls = array();
        if(isset($params['PageUrl']) && is_array($params['PageUrl']) && count($params['PageUrl']))
        {
            $valid=true;
            foreach($params['PageUrl'] as $i=>$item)
            {
                $pageUrls[$i] = new PageUrl();
                if(isset($params['PageUrl'][$i]))
                    $pageUrls[$i]->attributes=$params['PageUrl'][$i];
                if (isset($params['page_id']))
                    $pageUrls[$i]->page_id = (int) $params['page_id'];

                $valid=$pageUrls[$i]->validate() && $valid;
                if ($pageUrls[$i]->hasErrors())
                    Yii::log(CVarDumper::dumpAsString($pageUrls[$i]->getErrors()), CLogger::LEVEL_ERROR);
            }
            if($valid)  {
                foreach($pageUrls as $i=>$item)
                {
                    if (empty($pageUrls[$i]->url) && empty($pageUrls[$i]->url)) continue;
                    if ($i == 0)
                        $pageUrls[$i]->default = true;
                    $pageUrls[$i]->status = true;
                    if (! $pageUrls[$i]->save(false))
                        $this->result->fail(ERROR_HANDLING_DB, Yii::t('Quote.RequestQuote','Error while saving submitted data into database.'));
                }
            } else
                $this->result->fail(ERROR_INVALID_DATA, Yii::t('Quote.RequestQuote', 'Submitted data is missing or invalid.'));
        } else
            $pageUrls = array(new PageUrl());
        $this->result->processed('pageUrls', $pageUrls);
    }

    public function delete($params) {
        $ids = $this->getParam($params, 'ids', array());
        $deleteData = $this->getParam($params, 'delete_data', false);
        if ($ids == 0) {
            return $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page','Invalid ID.'));
        }

        if (!is_array($ids)) $ids = array($ids);
        foreach($ids as $id) {
            $model = Page::model()->findByPk($id);
            try {
                $model->delete();
                FSM::run('Cms.pageRevision.deleteAll', array('page_id'=>$id));
                FSM::run('Cms.pageUrl.deleteAllByPageId', array('page_id'=>$id));
                FSM::run('Cms.page.deleteCurrent', array('id'=>$id));
                //delete widget data
                if ($deleteData)
                {
                    //find all widget_data of page deleted
                    $criteria = new CDbCriteria;
                    $criteria->compare('page_id', $id);
                    $criteria->compare('widget_data_id', '>0');
                    $pageWidgets = PageWidget::model()->findAll($criteria);
                    if (count($pageWidgets))
                    {
                        $widgetDataIdsDelete = CHtml::listData($pageWidgets, 'id', 'widget_data_id');
                        //find all widget_data used by another page?
                        $criteria = new CDbCriteria;
                        $criteria->addInCondition('widget_data_id', $widgetDataIdsDelete);
                        $criteria->compare('page_id', '<>'.$id);
                        $pageWidgetsUsed = PageWidget::model()->findAll($criteria);
                        $widgetDataIds = array();
                        if (count($pageWidgetsUsed))
                            $widgetDataIds = CHtml::listData($pageWidgetsUsed, 'id', 'widget_data_id');
                        $widgetDataIdsDelete = array_diff($widgetDataIdsDelete, $widgetDataIds);
                        //delete widget data not used
                        if (count($widgetDataIdsDelete))
                        {
                            foreach ($widgetDataIdsDelete as $pageWidgetId => $widgetDataId)
                            {
                                foreach ($pageWidgets as $pageWidget)
                                {
                                    if ($pageWidget->id == $pageWidgetId)
                                    {
                                        $contentType = $pageWidget->contentType;
                                        if (is_object($contentType))
                                        {
                                            /** @var CActiveRecord */
                                            $model = Yii::createComponent(array('class'=>$contentType->model));
                                            if (is_object($model))
                                            {
                                                $model->deleteByPk($widgetDataId);
                                            }
                                            else
                                            {
                                                Yii::log('Not found model '.$contentType->model, CLogger::LEVEL_ERROR);
                                            }
                                        }
                                        else
                                        {
                                            Yii::log('Not found content type id: '.$contentTypeId, CLogger::LEVEL_ERROR);
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            Yii::trace('$widgetDataIdsDelete: '.CVarDumper::dump($widgetDataIdsDelete));
                            Yii::trace('$widgetDataIds: '.CVarDumper::dump($widgetDataIds));
                            Yii::trace('don not any widget data for delete');
                        }
                    }
                    else
                    {
                        Yii::trace('page_id: '.$id);
                        Yii::trace('don not any widget data for delete');
                    }
                }
                FSM::run('Cms.pageWidget.deleteAllByPageId', array('page_id'=>$id));
            } catch (CDbException $ex) {
                $this->result->fail(ERROR_HANDLING_DB, $ex->getMessage());
            }
        }
        return $this->result;
    }

    public function deleteBySite($params)
    {
        $siteId = $this->getParam($params, 'site_id', 0);
        if ($siteId)
        {
            $pages = Page::model()->findAllByAttributes(array('site_id'=>$siteId));
            if (count($pages))
            {
                $ids = CHtml::listData($pages, 'id', 'id');
                FSM::_run('Cms.page.delete', array('ids'=>$ids));
            }
        }
        return $this->result;
    }

    public function getList()
    {
        $criteria = new CDbCriteria();
        $criteria->order = 'title';
        $models = Page::model()->findAll($criteria);
        $this->result->processed('models', $models);
        return $this->result;
    }

    /**
    * Render a page
    * 
    * @param string url
    */
    public function renderPage($params) 
    {
        $url = $this->getParam($params,'url','','notag,xss,newline');
        $host = $this->getParam($params,'host',parse_url(Yii::app()->request->hostInfo, PHP_URL_HOST));

        // transalte Yii parameter markers back to user friendly parameter markers
        $url = strtr($url,'<>','[]');

        $content = $this->getParam($params,'content',array(),'xss,tag,newline');
        $html = '';
        $siteId = 0;
        if (empty($url) === false)
        {
            $workflowType = Workflow::TYPE_NORMAL;
            $result = FSM::run('Cms.workflow.lookup', array('host'=>$host));
            if ($result->hasErrors())
            {
                throw new CHttpException(404, 'Error, this domain might not be configured properly to work with our CMS.');
            }
            else
            {
                $siteId = $result->model->site_id;
                $workflowType = $result->model->type;
            }

            $criteria = new CDbCriteria();
            $criteria->with = array('pageUrls'=>array('joinType'=>'INNER JOIN', 'select'=>false));
            $criteria->compare('t.status', true);
            $criteria->compare('t.site_id', $siteId);

            if ($url != '/')
                $criteria->addSearchCondition('"pageUrls".url', $url, true, 'AND', 'LIKE');
            else
                $criteria->compare('"pageUrls".url', $url, false, 'AND');
            Yii::trace('Find page', 'PageService');
            $page = Page::model()->find($criteria);
            //register page title
            if (defined('Settings::SITE_NAME'))
                Yii::app()->controller->pageTitle = Settings::SITE_NAME;
            if (is_object($page))
            {
                //register page title
                Yii::app()->controller->pageTitle = $page->title;
                $allowCache = (boolean) ($page->hasAttribute('allow_cache') ? $page->allow_cache : false);                
                Yii::app()->controller->pageId = (int) $page->id;
                $revision = FSM::run('Cms.pageRevision.getCurrent', array('page_id'=>$page->id))->revision;
                $revisionPreview = 0;
                //preview
                if (isset($_GET['revision']))
                {
                    $revisionPreview = (int) $_GET['revision'];
                    if ($workflowType == Workflow::TYPE_INITITAL)
                    {
                        $revision = $revisionPreview;
                    }
                    else
                    {
                        if ($revisionPreview == $revision)
                            $revision = $revisionPreview;
                        else
                            $revision = 1;
                    }
                }elseif ($revision<=0)
                    $revision = 1;

                $result = FSM::run('Cms.PageRevision.get', array('id' => $revision, 'page_id'=>$page->id));
                if ($result->hasErrors())
                    throw new CHttpException(404, 'Page not found.');

                Yii::app()->controller->pageRevision = $revision;
                $pageRevision = $result->model;
                if (is_object($pageRevision))
                {
                    $template = $pageRevision->templateContent(array(
                    'condition'=>'"templateContent".status = :status',
                    'params'=>array(':status'=>true),
                    'with'=>array(
                    'template'=>array(
                    'select'=>false,
                    'joinType'=>'INNER JOIN',
                    'condition'=>'"template".status = :status',
                    'params'=>array(':status'=>true),
                    )
                    )
                    ));

                    // hack to return only data of this Flash Data page
                    /*if ($template->template->group=='flash') {
                    Yii::app()->controller->isFlashDataPage = true;
                    }*/

                    //Yii::app()->cache->flush();
                    //not cache data when edit page
                    $editMode = Yii::app()->session->contains('editMode') ? Yii::app()->session['editMode'] : false;
                    $allowCache = $allowCache && ($editMode === false);
                    if ($allowCache && Yii::app()->hasComponent('cachePage'))
                    {
                        $id = Yii::app()->cmsManager->workflow['url'].'#'.$page->alias;
                        $html = Yii::app()->cachePage->get($id);
                        //Yii::trace('$html '.$html);
                    }
                    else
                    {
                        $html = false;
                    }
                    if($html === false)
                    {
                        if (is_object($template))
                        {
                            //override css, js
                            if (count($pageRevision->js_files))
                                $template->js_files = $pageRevision->js_files;
                            if (count($pageRevision->css_files))
                                $template->css_files = $pageRevision->css_files;

                            //page info
                            if (Yii::app()->user->isGuest === false)
                            {
                                $isActiveInLive = '';
                                if ($workflowType != Workflow::TYPE_FINAL && $this->isActiveInLive($page->id, $revision))
                                {
                                    $isActiveInLive = '.addClass("is_active_in_live")';
                                }
                                $script = "
                                jQuery('body')
                                .addClass('page_{$page->id}')
                                .addClass('revision_{$revision}')
                                ".$isActiveInLive."
                                .addClass('template_{$template->template_id}')
                                .addClass('template_revision_{$template->revision_id}');";
                                Yii::app()->controller->templateId = $template->template_id;
                                Yii::app()->controller->templateRevision = $template->revision_id;
                                Yii::app()->clientScript->registerScript(__CLASS__.'#Page', $script, CClientScript::POS_READY);
                                if ($workflowType == Workflow::TYPE_FINAL)
                                {
                                    $script = "jQuery('#sb-page-controls').addClass('live');";
                                    Yii::app()->clientScript->registerScript(__CLASS__.'#BackgroundToolbar', $script, CClientScript::POS_READY);
                                }
                            }
                        }
                        elseif ($page->type != Page::TYPE_STANDARD)
                        {
                            throw new CHttpException(404, 'Oups, Page not found.');
                        }

                        //render page content
                        $data = null;
                        if ($page->type === Page::TYPE_STANDARD)
                        {
                            $data = array('content'=>Yii::app()->controller->renderPartial($page->view,$content, true));
                        }

                        $criteria = array(
                        'condition'=>'revision_id=:revision_id', 
                        'params'=>array(':revision_id'=>$revision),
                        );

                        if ((Yii::app()->session->contains('editMode') && Yii::app()->session['editMode']) === false)
                        {
                            $criteria['condition'] .= ' AND status=:status';
                            $criteria['params'][':status'] = true;
                        }
                        //get widgets of current revision
                        $widgets = $page->pageWidgets($criteria);

                        $html = $this->parseTemplateContent($template, $widgets, $siteId, $data);
                        if ($allowCache && Yii::app()->hasComponent('cachePage'))
                        {
                            $expire = defined('Settings::CACHE_EXPIRE') ? Settings::CACHE_EXPIRE : 15*60;
                            Yii::app()->cachePage->set($id,$html, $expire);
                        }
                    }
                }
                else
                    throw new CHttpException(404, 'Oups, Page not found.');
            }
            else
                throw new CHttpException(404, 'Page not found.');
        }
        else
            throw new CHttpException(400, 'Invalid requested URL.');

        //render static widgets
        //        $html .= FSM::run('Cms.pageWidget.renderStaticWidget', array('site_id'=>$siteId))->html;

        $this->result->processed('html',$html);
        return $this->result;
    }

    protected function parseTemplateContent($template, $widgets, $siteId, $data=null)
    {
        // register template JS files
        $this->registerFileScripts($template);
        /*if ($template->js_files)
        {
        //eval("\$template->js_files = {$template->js_files};");
        foreach($template->js_files as $file){
        $file = ltrim(str_replace(themeUrl().'/scripts/','','/'.$file),'/');                
        Yii::app()->clientScript->registerScriptFile(themeUrl().'/scripts/'.$file);
        }
        }
        // register template CSS files
        if ($template->css_files)
        {
        //eval("\$template->css_files = {$template->css_files};");
        foreach($template->css_files as $file){
        $file = ltrim(str_replace(themeUrl().'/styles/','','/'.$file),'/');
        Yii::app()->clientScript->registerCssFile(themeUrl().'/styles/'.$file);
        }
        }*/

        $html = array();
        foreach($widgets as $widget)
        {
            $result = FSM::_run('Cms.PageWidget.renderHtml',array('id' => $widget->id));
            if ($result->hasErrors() == false) {
                $html[$widget->container][] = $result->html;
            } else {
                // nothing to do, the PageWidget.renderHTML should render some error message as the widget content
            }
        }

        //Yii::trace('Static widget: ', 'WidgetDOM');
        //static widget
        /*
        $staticWidgets = FSM::run('Cms.widgetData.getStaticWidget', array('site_id'=>$siteId, 'status'=>true))->models;
        if (is_array($staticWidgets) && count($staticWidgets))
        {
        foreach ($staticWidgets as $staticWidget)
        {
        if (is_object($staticWidget->widget) && is_array($staticWidget->widget->layouts))
        {
        $layoutId = $staticWidget->widget->layouts[0]->id;
        $result = FSM::run('Cms.pageWidget.renderHtml', array(
        'widget_layout_id'=>$layoutId,
        'widget_data_id'=>$staticWidget->id,
        ));
        $html[$staticWidget->container][] = $result->html;
        //Yii::trace('$result->html: '.get_class($result->html), 'WidgetDOM');
        }
        }
        }
        */

        $containers = array_keys($html);

        //parse and register js, css
        foreach($containers as $container)
        {
            foreach($html[$container] as $index => $widgetHtmlDoc)
            {
                $this->registerScript($widgetHtmlDoc);
                $this->registerCss($widgetHtmlDoc);
                $html[$container][$index] = $widgetHtmlDoc;
            }
        }

        if (is_object($template))
        {
            // we need the view file of the template's html so we can render it
            // rendering the view file allow us to support PHP code in template
            $template->ensureViewExist();

            //parse and register js, css in template
            //$templateContent = Yii::app()->controller->renderPartial('//'.$template->View, null, true);
            //$this->parseScripts($templateContent);

            //        $templateHtml = Yii::app()->controller->renderPartial('//'.$template->View, null, true);
            // temporarily we use render() instead of renderPartial as the nested template mechanism is not implemented

            //            if (get_class(Yii::app()->controller) == 'DefaultCmsController' || Yii::app()->controller->layout === null)
            //                Yii::app()->controller->layout = FSM::_run('Cms.Site.getMasterLayout', array('id' => $siteId))->layout;

            $templateHtml = Yii::app()->controller->renderPartial('//'.$template->View, $data, true);
            Yii::trace(CVarDumper::dumpAsString($templateHtml), 'render');
            $templateHtml = $this->renderNestedTemplate($template, $templateHtml);
        }
        else
        {
            $templateHtml = $data['content'];
        }

        //parse and register js, css in template use tags <js/> <css/>
        /*if (Yii::app()->controller->isFlashDataPage && !Yii::app()->controller->allowEdit){
        Yii::app()->controller->layout = false;
        cs()->reset();
        } else {*/
        //            var_dump(Yii::app()->controller->layout);
        $this->parseScripts($templateHtml);
        //        }

        //register Toolbar
        $toolbar = Yii::app()->controller->widget('Cms.components.ToolbarWidget', array('visible'=>!Yii::app()->request->getParam('preview', false)), true);

        $templateHtml = Yii::app()->controller->renderText($templateHtml, true);

        $doc = new FDom();
        $doc->loadXMLwithEntities($templateHtml,'html'); //this work with render() only, when nested template is implemented, use 'root'
        $query = new DOMXPath($doc);

        //apply layouts
        $this->renderLayout($doc, $query, $this->getAllContainer($query));

        // render content
        foreach($containers as $container)
        {
            $parent = null;
            if ($container == 'cms-header')
            {
                //insert before close head
                $entries = $doc->getElementsByTagName('head');
                if ($entries->length)
                    $parent = $entries->item(0);
                else
                    $parent = null;
                //Yii::trace('head', 'WidgetDOM');
            }
            elseif ($container == 'cms-footer')
            {
                //insert before close body
                $entries = $doc->getElementsByTagName('body');
                if ($entries->length)
                    $parent = $entries->item(0);
                else
                    $parent = null;
                //Yii::trace('body', 'WidgetDOM');
            }
            else
            {
                $entries = $query->query("//*[@id='{$container}']");
                if ($entries->length)
                    $parent = $entries->item(0);
                else
                    $parent = null;
                //Yii::trace('query:'.$container, 'WidgetDOM');
            }

            //Yii::trace('$parent: '.get_class($parent), 'WidgetDOM');
            //replace correct content
            if ($parent instanceof DOMElement)
            {
                foreach($html[$container] as $widgetHtmlDoc)
                {
                    //Yii::trace('$widgetHtmlDoc->saveXML: '.$widgetHtmlDoc->saveXML(), 'WidgetDOM');
                    $node = $widgetHtmlDoc->getElementsByTagName('root');                    
                    if ($node->length)
                    {
                        $root = $node->item(0);
                        $this->validateContent($root, $parent, $doc);
                    }
                }
            }
        }
        //remove js, css in template
        //Yii::trace('remove js, css in template', 'WidgetDOM');
        $this->removeElementsByTag($doc, 'js');
        $this->removeElementsByTag($doc, 'css');
        $node = $doc->getElementsByTagName('com');
        while ($node->length)
        {
            $com = $node->item(0);
            $parent = $com->parentNode;
            Yii::trace('$parent: '.$doc->saveXML($parent), 'Node');
            if ($com->hasChildNodes())
            {
                foreach ($com->childNodes as $item)
                {                            
                    $item = $doc->importNode($item->cloneNode(true), true);
                    $parent->appendChild($item);
                }                
            }
            $parent->removeChild($com);
            Yii::trace('$parent: '.$doc->saveXML($parent), 'Node');
        }

        //Yii::trace('saveHTML: '.$doc->saveHTML(), 'WidgetDOM');

        //        return $doc->saveHTML();

        //insert html toolbar
        $this->addToolbar($toolbar, $doc);

        $html = $doc->saveHTML();
        $html = str_replace('<br></br>','<br />',$html);
        // the saveHTML cannot use NOEMTYPTAG option and it will change <br/> into <br></br>, same for <hr/>
        //        $html = $doc->saveXML($doc->getElementsByTagName('html')->item(0), !LIBXML_NOEMPTYTAG);
        return $html;
        //        return $doc->saveXML($doc->getElementsByTagName('html')->item(0), !LIBXML_NOEMPTYTAG);
    }

    protected function addToolbar($toolbar, &$doc)
    {
        $body = $doc->getElementsByTagName('body')->item(0);
        if (!is_object($body)) return;
        // Create a new document
        $newdoc = new DOMDocument;
        $newdoc->formatOutput = true;
        $newdoc->loadXML("<root>".$toolbar."</root>");
        $node = $newdoc->getElementsByTagName('root');
        if ($node->length)
        {
            $root = $node->item(0);
            if ($root->hasChildNodes())
            {
                foreach ($root->childNodes as $item)
                {                            
                    $item = $doc->importNode($item->cloneNode(true), true);
                    $body->appendChild($item);
                }                
            }
        }
    }

    protected function renderNestedTemplate($template, $content)
    {
        Yii::trace(__CLASS__.'::'.__FUNCTION__, 'NestedTemplate');
        Yii::trace(CVarDumper::dumpAsString($template->parent), 'NestedTemplate');
        if (is_object($template->parent))
        {//echo $template->id,' ',$template->parent->id;
            if ($template->parent->template->MasterLayout) {
                Yii::app()->controller->layout = '//layouts/'.$template->parent->View;
            } else {
                $parent = $template->parent;
                //register js, css of parent template
                $this->registerFileScripts($parent);

                //render content
                Yii::app()->controller->beginClip('content');
                $parent->ensureViewExist();
                //            echo $template->View;
                Yii::app()->controller->beginWidget('Cms.components.ContentDecorator',array('view'=>'//'.$parent->View));
                echo $content;
                Yii::app()->controller->endWidget('Cms.components.ContentDecorator');
                Yii::app()->controller->endClip();
                if (!($parent->parent->template->MasterLayout))
                    $content = $this->renderNestedTemplate($parent->parent, Yii::app()->controller->clips['content']);
                else
                    $content = Yii::app()->controller->clips['content'];
            }
        }
        return $content;
    }

    /**
    * parse and register js, css in template use tags <js/> <css/>
    * 
    * @param string $templateContent
    */
    protected function parseScripts($html)
    {
        $doc = new FDom();
        libxml_use_internal_errors(true);
        $templateXML = $doc->loadXMLwithEntities($html);
        if ($templateXML)
        {
            $this->registerScript($doc);
            $this->registerCss($doc);
        }
        else
        {
            $errors = libxml_get_errors();

            foreach ($errors as $error)
            {
                $return = trim($error->message) .
                "\n  Line: $error->line" .
                "\n  Column: $error->column";
                Yii::log($return, CLogger::LEVEL_ERROR);
            }
            libxml_clear_errors();
            throw new CException('Template is not well-formed, check the template for your HTML code, especially in case it is mixed with PHP code.');
        }
    }

    /**
    * register js, css files of template
    * 
    * @param Template $template
    */
    protected function registerFileScripts($template)
    {
        if (! is_object($template)) return;
        // register template JS files
        if ($template->js_files)
        {
            //eval("\$template->js_files = {$template->js_files};");
            foreach($template->js_files as $file){
                $file = ltrim(str_replace(themeUrl().'/scripts/','','/'.$file),'/');                
                Yii::app()->clientScript->registerScriptFile(themeUrl().'/scripts/'.$file);
            }
        }
        // register template CSS files
        if ($template->css_files)
        {
            //eval("\$template->css_files = {$template->css_files};");
            foreach($template->css_files as $file){
                $file = ltrim(str_replace(themeUrl().'/styles/','','/'.$file),'/');
                Yii::app()->clientScript->registerCssFile(themeUrl().'/styles/'.$file);
            }
        }
    }

    protected function validateContent($root, $parent, &$doc)
    {
        if (($root instanceof DOMNode) && $root->hasChildNodes())
        {
            foreach ($root->childNodes as $child)
            {
                if ($child instanceof DOMText)
                {
                    $text = $child->wholeText;
                    $text = trim($text);
                    if (empty($text))
                        continue;
                }
                //Yii::trace('$parent nodeName: '.$parent->nodeName, 'WidgetDOM');
                //Yii::trace('$child nodeName: '.$child->nodeName, 'WidgetDOM');
                if ($parent->nodeName == 'head')
                {
                    $headTags = array('base', 'link', 'meta', 'script', 'style', 'title');
                    foreach ($headTags as $tag)
                        $this->addHeadElements($doc, $child, $parent, $tag);
                }
                elseif ($parent->nodeName == 'body')
                {
                    if (get_class($child) == 'DOMNode')
                    {
                        $class = $child->hasAttribute('class') ? $child->getAttribute('class') : '';
                        if (empty($class) === false && strpos($class, 'sb-widget') !== false && $child->hasChildNodes())
                        {
                            foreach ($child->childNodes as $item)
                            {
                                $item = $doc->importNode($item, true);
                                $parent->appendChild($item);
                            }
                        }
                        else
                        {
                            $child = $doc->importNode($child, true);
                            $parent->appendChild($child);
                        }
                    }
                }
                else
                {
                    $child = $doc->importNode($child, true);
                    $parent->appendChild($child);
                }
            }
        }
    }

    protected function addHeadElements($doc, $child, $parent, $tag)
    {
        $elements = $child->getElementsByTagName($tag);
        if ($elements->length)
        {
            foreach ($elements as $element)
            {
                $element = $doc->importNode($element, true);
                $parent->appendChild($element);
            }
        }
    }

    protected function removeElementsByTag(&$doc, $tag)
    {
        $elements = $doc->getElementsByTagName($tag);
        if ($elements->length)
        {
            $element = $elements->item(0);
            if (is_object($element))
            {
                $parent = $element->parentNode;
                $parent->replaceChild(new DOMText(), $element);
                $this->removeElementsByTag($doc, $tag);
            }
        }
    }

    protected function registerScript(&$dom)
    {
        $scripts = $dom->getElementsByTagName('js');
        $count = $scripts->length;
        for ($i=0; $i < $count; $i++)
        {
            $script = $scripts->item($i);
            $position = $script->getAttribute('position');
            switch($position)
            {
                case 'begin':
                    $position = CClientScript::POS_BEGIN;
                    break;
                case 'end':
                    $position = CClientScript::POS_END;
                    break;
                case 'load':
                    $position = CClientScript::POS_LOAD;
                    break;
                case 'head':
                    $position = CClientScript::POS_HEAD;
                    break;
                case 'ready':
                default:
                    $position = CClientScript::POS_READY;
            }
            $jsId = $script->getAttribute('id');
            if (($js = $script->nodeValue) == '')
            {
                $js = ltrim(str_replace(themeUrl().'/scripts/','','/'.$script->getAttribute('script')),'/');
                Yii::app()->clientScript->registerScriptFile(themeUrl().'/scripts/'.$js, $position);
            }
            elseif (empty($jsId) === false)
            {
                Yii::app()->clientScript->registerScript($jsId, $js, $position);                   
            }
            Yii::trace('$jsId: '.$jsId, 'WidgetDOM');
        }
    }

    protected function registerCss(&$dom)
    {
        $scripts = $dom->getElementsByTagName('css');
        $count = $scripts->length;
        for ($i=0; $i < $count; $i++)
        {
            $script = $scripts->item($i);
            $cssId = $script->getAttribute('id');
            // css media type
            if ($media = $script->getAttribute('media') == '') $media = 'screen';

            if (($css = $script->nodeValue) == '')
            {
                $css = ltrim(str_replace(themeUrl().'/styles/','','/'.$script->getAttribute('link')),'/');
                Yii::app()->clientScript->registerCssFile(themeUrl().'/styles/'.$css,$media);
            }
            else
            {
                Yii::app()->clientScript->registerCss($cssId, $css, $media);
            }
            Yii::trace('$cssId: '.$cssId, 'WidgetDOM');
        }
    }

    public function editMode($params)
    {
        $editMode = Yii::app()->session->contains('editMode') ? Yii::app()->session['editMode'] : false;
        //toggle edit mode
        Yii::app()->session['editMode'] = !$editMode;
        $this->result->processed('editMode', $editMode);
        return $this->result;
    }

    //overide nested 
    public function buildTree($params = null)
    {
        $params['attributes'] = array('title', 'alias', 'site_id', 'workfollow_id');
        return $this->asa('nested')->buildTree($params);
    }

    public function getParents($params)
    {
        $id = $this->getParam($params, 'id', 0);
        $data = $this->buildTree(array())->tree;
        if ($id)
        {
            $params['attributes'] = array('title', 'alias', 'site_id', 'workfollow_id');
            $subTree = $this->buildSubTree($params)->tree;
            Yii::trace('$subTree:'.CVarDumper::dumpAsString($subTree));
            foreach ($subTree as $pageId => $item)
                if (isset($data[$pageId]))
                    unset($data[$pageId]);
                //remove current page
                if (isset($data[$id]))
                unset($data[$id]);
        }
        Yii::trace('$params:'.CVarDumper::dumpAsString($params).'; '.CVarDumper::dumpAsString($data));

        $parents = array();
        if (count($data))
        {
            foreach ($data as $id => $item)
            {
                $parents[$id] = str_repeat('--', $item['level']).$item['title'];
            }
        }

        $this->result->processed('parents', $parents);
        return $this->result;
    }

    public function changeStatus($params) {
        $ids = $this->getParam($params, 'ids', array());
        $value = $this->getParam($params, 'value', false);

        if (count($ids) <= 0)
            return $this->result;

        $criteria = new CDbCriteria();
        $criteria->addInCondition('id', $ids);
        Page::model()->updateAll(array('status'=>$value), $criteria);

        return $this->result;
    }

    public function includeInSitemap($params) {
        $ids = $this->getParam($params, 'ids', array());
        $value = $this->getParam($params, 'value', false);

        if (count($ids) <= 0)
            return $this->result;

        $criteria = new CDbCriteria();
        $criteria->addInCondition('id', $ids);
        Page::model()->updateAll(array('include_in_sitemap'=>$value), $criteria);

        return $this->result;
    }

    public function revert($params)
    {
        $pageId = $this->getParam($params, 'page_id', 0);
        $revision = $this->getParam($params, 'revision', 0);
        $workflowUrl = $this->getParam($params, 'workflow_url', parse_url(Yii::app()->request->hostInfo, PHP_URL_HOST));
        $status = false;
        if ($pageId && $revision)
        {
            $result = FSM::run('Cms.Workflow.lookup', array('host'=>$workflowUrl));
            if (!$result->hasErrors())
            {
                $workflow = $result->model;
                $command = Yii::app()->db->createCommand();
                //remove old current
                $command->delete(SITE_TABLE_PREFIX.'page_current_revision', 
                'page_id=:page_id AND workflow_id=:workflow_id',
                array(
                ':page_id'=>$pageId,
                ':workflow_id'=>$workflow->id,
                )
                );
                //insert
                $command->insert(SITE_TABLE_PREFIX.'page_current_revision', array(
                'page_id'=>$pageId,
                'workflow_id'=>$workflow->id,
                'revision'=>$revision,
                ));
                $status = true;
            }
        }
        $this->result->processed('status', $status);
        return $this->result;
    }

    public function initCurrentByWorkflow($params)
    {
        $workflowId = $this->getParam($params, 'workflow_id', 0);
        $siteId = $this->getParam($params, 'site_id', 0);
        $models = Page::model()->findAllByAttributes(array('site_id'=>$siteId));
        if (count($models))
        {
            $db = Yii::app()->db;
            foreach ($models as $model)
            {
                $result = FSM::run('Cms.pageRevision.getNextRevision', array('page_id'=>$model->id));
                if (!$result->hasErrors())
                {
                    $command = Yii::app()->db->createCommand();
                    $count = $command
                    ->select('COUNT(*)')
                    ->from(SITE_TABLE_PREFIX.'page_current_revision')
                    ->where('page_id=:page_id AND workflow_id=:workflow_id AND revision=:revision', array(
                    ':page_id'=>$model->id,
                    ':workflow_id'=>$workflowId,
                    ':revision'=>$result->revision-1,
                    ))
                    ->queryScalar();
                    if (!$count)
                    {
                        $command->insert(SITE_TABLE_PREFIX.'page_current_revision', array(
                        'page_id'=>$model->id,
                        'workflow_id'=>$workflowId,
                        'revision'=>$result->revision,
                        ));
                    }
                }
            }
        }
        return $this->result;
    }

    public function deleteCurrentByWorkflow($params)
    {
        $workflowId = $this->getParam($params, 'workflow_id', 0);
        $db = Yii::app()->db;
        $command = $db->createCommand('DELETE FROM '.SITE_TABLE_PREFIX.'page_current_revision WHERE workflow_id=:workflow_id');
        $command->bindValue(':workflow_id', $workflowId);
        $command->execute();
        return $this->result;
    }

    public function initCurrentByPage($params)
    {
        $pageId = $this->getParam($params, 'id', 0);
        $siteId = $this->getParam($params, 'site_id', 0);
        $models = FSM::run('Cms.workflow.getListBySite', array('site_id'=>$siteId))->models;
        if (count($models))
        {
            $db = Yii::app()->db;
            foreach ($models as $model)
            {
                if ($model->type != Workflow::TYPE_INITITAL)
                    continue;

                $command = Yii::app()->db->createCommand();
                $count = $command
                ->select('COUNT(*)')
                ->from(SITE_TABLE_PREFIX.'page_current_revision')
                ->where('page_id=:page_id AND workflow_id=:workflow_id AND revision=:revision', array(
                ':page_id'=>$pageId,
                ':workflow_id'=>$model->id,
                ':revision'=>1,
                ))
                ->queryScalar();
                if (!$count)
                {
                    $command->insert(SITE_TABLE_PREFIX.'page_current_revision', array(
                    'page_id'=>$pageId,
                    'workflow_id'=>$model->id,
                    'revision'=>1,
                    ));
                }
            }
        }
        return $this->result;
    }

    public function deleteCurrent($params)
    {
        $pageId = $this->getParam($params, 'id', 0);
        $db = Yii::app()->db;
        $command = $db->createCommand('DELETE FROM '.SITE_TABLE_PREFIX.'page_current_revision WHERE page_id=:page_id');
        $command->bindValue(':page_id', $pageId);
        $command->execute();
        return $this->result;
    }

    public function reorder($params)
    {
        $ids = $this->getParam($params, 'items', array());
        if (count($ids)) {
            foreach ($ids as $id => $parentId) {
                $orders = array();
                if ($parentId == 'root') {
                    $orders = array_keys($ids, $parentId);
                    $parentId = 0;
                }
                else {
                    $parentId = (int) $parentId;
                    $orders = array_keys($ids, $parentId);
                }
                $order = 0;
                if (count($orders))
                    $order = (int) array_search($id, $orders);
                $order++;
                Page::model()->updateByPk($id, array(
                'parent_id'=>$parentId,
                'ordering'=>$order,
                ));
            }
        }
        return $this->result;
    }

    /**
    * copy page from site to site
    * 
    * @param array $params
    * <ul>
    *   <li>source_site_id: int, required, copy pages from source site_id, if not set, source_site_id will
    * get default site{@see Cms.site.getDefault service}</li>
    *   <li>target_site_id: array, required, copy pages to target site_id</li>
    *   <li>page_id: array, required, copy pages</li>
    *   <li>parent_id: int, set parent of target page</li>
    *   <li>ordering: int, set ordering of target page</li>
    *   <li>active_workflow: boolean, Automatical set active revisions if target workflow found</li>
    *   <li>revisions: array,  array('all', 'active') Which revisions you want to copy</li>
    * </ul>
    * 
    * @return FServiceModel
    */
    public function copy($params)
    {
        $defaultSiteId = Yii::app()->cmsManager->site['id'];
        $sourceSiteId = $this->getParam($params, 'source_site_id', $defaultSiteId);
        $targetSiteIds = $this->getParam($params, 'target_site_id', array());

        $pageIds = $this->getParam($params, 'page_id', array());
        $parentId = $this->getParam($params, 'parent_id', 0);
        $ordering = $this->getParam($params, 'ordering', 0);

        $title = $this->getParam($params, 'page_title', '');
        $activeWorkflow = $this->getParam($params, 'active_workflow', false);

        $linkData = $this->getParam($params, 'link_data', false);
        $copyRevision = isset($params['copy_revision']) ? $params['copy_revision'] : 'all';//$this->getParam($params, 'copy_revision', 'all');

        $models = array();
        if ($sourceSiteId && count($targetSiteIds) && count($pageIds))
        {
            //find all pages sources
            $criteria = new CDbCriteria();
            $criteria->compare('site_id', $sourceSiteId);
            $criteria->addInCondition('id', $pageIds);
            $items = Page::model()->findAll($criteria);
            //copy to target site
            if (count($items))
            {   
                // copy page by page
                foreach ($items as $model)
                {
                    $sourcePageId = $model->id;
                    // copy the page to each site
                    foreach ($targetSiteIds as $targetSiteId)
                    {
                        $alias = null;
                        //fix bug required view, route for Standard page
                        $attributes = $model->attributes;
                        if ($model->type == Page::TYPE_CMS)
                        {
                            unset($attributes['route']);
                            unset($attributes['view']);
                        }
                        $attributes = array_keys($attributes);

                        //duplicate page
                        if (empty($title) === false)
                        {
                            $model->title = $title;
                            $alias = toSlug($title);
                            $model->alias = $alias;
                        }
                        $criteria = new CDbCriteria();
                        $criteria->compare('site_id', $targetSiteId);
                        $criteria->compare('alias', $model->alias);
                        $pageExist = Page::model()->find($criteria);
                        //page is exists?
                        //true, create new revision
                        $copyData = false;
                        if (is_object($pageExist))
                        {
                            array_push($models, $pageExist);
                            $targetPageId = $pageExist->id;
                            $copyData = true;
                        }
                        else
                        {
                            //create new
                            $model->setIsNewRecord(true);
                            $model->id = null;
                            $model->parent_id = $parentId;
                            $model->site_id = $targetSiteId;
                            $model->ordering = $ordering;
                            if (!$model->save(true, $attributes))
                            {
                                Yii::log(CVarDumper::dumpAsString($model->getErrors()), CLogger::LEVEL_ERROR);
                            }
                            else
                            {
                                array_push($models, $model);
                                $targetPageId = $model->id;
                                $copyData = true;
                                //auto active page in initial workflow
                                FSM::run('Cms.Page.initCurrentByPage', array('id'=>$targetPageId,'site_id'=>$targetSiteId));
                            }
                        }

                        //copy page data
                        if ($copyData)
                        {

                            if (is_null($alias))//copy page url from source page
                                FSM::run('Cms.PageUrl.copy', array('source_page_id'=>$sourcePageId, 'target_page_id'=>$targetPageId));
                            else//create new page url = alias
                            {
                                FSM::run('Cms.PageUrl.save', array(
                                'PageUrl'=>array(
                                'page_id'=>$targetPageId,
                                'url'=>$alias,
                                'status'=>true,
                                'default'=>true,
                                )
                                ));
                            }
                            FSM::run('Cms.PageRevision.copy', array(
                            'source_site_id'=>$sourceSiteId,
                            'target_site_id'=>$targetSiteId,
                            'source_page_id'=>$sourcePageId,
                            'target_page_id'=>$targetPageId,
                            'copy_revision'=>$copyRevision,
                            'active_workflow'=>$activeWorkflow,
                            'link_data'=>$linkData,
                            ));
                        }
                    }
                }
            }
        }
        else
            $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page', 'Submitted data is missing or invalid.'));

        $this->result->processed('models', $models);
        return $this->result;
    }

    public function isExistAlias($params)
    {
        $siteId = $this->getParam($params, 'site_id', '');
        $title = $this->getParam($params, 'title', '');

        $exist = null;
        if (empty($title) || !$siteId)
        {
            $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page', 'Submitted data is missing or invalid.'));
        }
        else
        {
            $alias = toSlug($title);
            $criteria = new CDbCriteria();
            $criteria->compare('site_id', $siteId);
            $criteria->compare('alias', $alias);
            $exist = Page::model()->exists($criteria);
        }

        $this->result->processed('exist', $exist);
        return $this->result;
    }

    protected function isActiveInLive($pageId, $revision)
    {
        $criteria = new CDbCriteria();
        $criteria->join = 'INNER JOIN '.SITE_TABLE_PREFIX.'page_current_revision pcr ON pcr.workflow_id = t.id';
        $criteria->compare('pcr.page_id', $pageId);
        $criteria->compare('pcr.revision', $revision);
        $criteria->compare('type', Workflow::TYPE_FINAL);
        return Workflow::model()->exists($criteria);
    }

    public function getListByWidgetLayout($params)
    {
        $widgetLayoutId = $this->getParam($params, 'widget_layout_id', 0);
        $siteId = $this->getParam($params, 'site_id', Yii::app()->cmsManager->site['id']);

        $criteria = new CDbCriteria();
        $criteria->join = 'INNER JOIN '.SITE_TABLE_PREFIX.'page_widget pw ON pw.page_id = t.id';
        $criteria->compare('pw.widget_layout_id', $widgetLayoutId);
        $criteria->compare('t.site_id', $siteId);
        $criteria->order = 'title';
        $criteria->distinct = true;
        $models = Page::model()->findAll($criteria);
        $this->result->processed('models', $models);
        return $this->result;
    }

    public function findByAlias($params)
    {
        $alias = $this->getParam($params, 'alias', '');
        $siteId = $this->getParam($params, 'site_id', 0);
        $status = (boolean) $this->getParam($params, 'status', Page::STATUS_ACTIVE);

        //lookup
        if ($siteId == 0)
        {
            $site = FSM::_run('Cms.site.lookup')->model;
            if (is_object($site))
                $siteId = (int) $site->id;
        }

        $criteria = new CDbCriteria();
        $criteria->compare('alias', $alias);
        $criteria->compare('site_id', $siteId);
        $model = Page::model()->find($criteria);

        $this->result->processed('model', $model);
        return $this->result;
    }

    public function getPageDetails($params)
    {
        $pageId = $this->getParam($params, 'page_id', 0);
        $revision = $this->getParam($params, 'revision', 0);
        $workflowId = $this->getParam($params, 'workflow_id', 0);

        $criteria = new CDbCriteria();
        $criteria->select = 'title, site_id';
        $criteria->with = array(
        'revisions'=>array(
        'select'=>'id',
        'together'=>true,
        'with'=>array(
        'templateContent'=>array(
        'select'=>array('id', 'revision_id'),
        'together'=>true,
        'with'=>array(
        'template'=>array(
        'select'=>'name',
        'together'=>true,
        )
        )
        )
        )
        ),
        'pageWidgets'=>array(
        //                'select'=>'container, ordering',
        'together'=>true,
        /*'with'=>array(
        'widgetLayout'=>array(
        'select'=>'name',
        'together'=>true,
        'with'=>array(
        'widget'=>array(
        'select'=>'name, type',
        'together'=>true,
        )
        )
        ),
        'widgetData'=>array(
        'select'=>'name',
        'together'=>true,
        ),
        )*/
        )
        );
        if ($workflowId)
            $criteria->join = 'INNER JOIN '.SITE_TABLE_PREFIX.'page_current_revision pcr ON pcr.page_id = t.id AND revision = '.$revision.' AND workflow_id = '.$workflowId;
        $criteria->compare('revisions.id', $revision);
        $criteria->compare('"pageWidgets".revision_id', $revision);
        $model = Page::model()->findByPk($pageId, $criteria);
        if (!is_object($model))
        {
            $criteria = new CDbCriteria();
            $criteria->select = 'title, site_id';
            $criteria->with = array(
            'revisions'=>array(
            'select'=>'id',
            'together'=>true,
            'with'=>array(
            'templateContent'=>array(
            'select'=>array('id', 'revision_id'),
            'together'=>true,
            'with'=>array(
            'template'=>array(
            'select'=>'name',
            'together'=>true,
            )
            )
            )
            )
            ),
            );
            if ($workflowId)
                $criteria->join = 'INNER JOIN '.SITE_TABLE_PREFIX.'page_current_revision pcr ON pcr.page_id = t.id AND revision = '.$revision.' AND workflow_id = '.$workflowId;
            $criteria->compare('revisions.id', $revision);
            $model = Page::model()->findByPk((int) $pageId, $criteria);
        }
        if (!is_object($model))
        {
            $criteria = new CDbCriteria();
            $criteria->select = 'title, site_id';
            $criteria->with = array(
            'revisions'=>array(
            'select'=>'id',
            'together'=>true,
            'with'=>array(
            'templateContent'=>array(
            'select'=>array('id', 'revision_id'),
            'together'=>true,
            'with'=>array(
            'template'=>array(
            'select'=>'name',
            'together'=>true,
            )
            )
            )
            )
            ),
            );
            if ($workflowId)
                $criteria->join = 'INNER JOIN page_current_revision pcr ON pcr.page_id = t.id AND revision = '.$revision.' AND workflow_id = '.$workflowId;
            $criteria->compare('revisions.id', $revision);
            $model = Page::model()->findByPk((int) $pageId, $criteria);
        }
        return $this->result->processed('model', $model);
    }

    public function usedInTemplate($params)
    {
        $templateId = $this->getParam($params, 'template_id', 0);
        $revisionId = $this->getParam($params, 'revision_id', 0);

        if (($templateId && $revisionId) === false)
        {
            $this->result->fail(ERROR_INVALID_DATA, Yii::t('CmsModule.Page', 'template_id, revision_id is required.'));
            return $this->result->processed('data', false);
        }

        $criteria = new CDbCriteria();
        $criteria->select = array('id', 'title', 'site_id');
        $criteria->with = array(
        'revisions'=>array(
        'select'=>false,
        'joinType'=>'INNER JOIN',
        'with'=>array(
        'templateContent'=>array(
        'select'=>false,
        'joinType'=>'INNER JOIN',
        ),
        )
        ),
        'site'=>array(
        'select'=>'name',
        )
        );
        $criteria->compare('"templateContent".template_id', $templateId);
        $criteria->compare('"templateContent".revision_id', $revisionId);
        $models = Page::model()->findAll($criteria);
        return $this->result->processed('data', $models);
    }

    /**
    * apply layout for container
    * 
    * @param FDom $doc
    * @param DOMXPath $query
    * @param array $containers
    */
    public function renderLayout($doc, $query, $containers)
    {
        if (count($containers))
        {
            foreach ($containers as $container)
            {
                $result = FSM::_run('Cms.LayoutContainer.findLayoutsByContainer', array(
                'container'=>$container,
                'page_id'=>Yii::app()->controller->pageId,
                'revision_id'=>Yii::app()->controller->pageRevision,
                ));
                if ($result->html !== false)
                {
                    //import node
                    $newdoc = new DOMDocument;
                    $newdoc->loadXML($result->html);
                    $newContainerDOM = $doc->importNode($newdoc->documentElement, true);
                    /*echo CHtml::encode($newdoc->saveXML($newContainerDOM));
                    Yii::app()->end();*/
                    //replace html of current container = new html
                    $entries = $query->query("//*[@id='{$container}']");

                    //temp document clone exists content in container
                    $tempdoc = new DOMDocument;
                    $tempdoc->loadXML('<root></root>');

                    if ($entries->length)
                    {
                        $containerDOM = $entries->item(0);
                        $children = $containerDOM->childNodes;
                        //                        echo CHtml::encode('length '.$children->length);
                        if ($children->length)
                        {
                            foreach ($children as $child)
                            {
                                $tempChild = $tempdoc->importNode($child, true);
                                $tempdoc->documentElement->appendChild($tempChild);
                            }
                        }
                        $containerDOM->parentNode->replaceChild($newContainerDOM, $containerDOM);
                        //                        echo CHtml::encode($doc->saveXML($containerDOM->parentNode));
                        //                        Yii::app()->end();
                    }

                    //                    echo CHtml::encode($tempdoc->saveXML($tempdoc->documentElement));
                    //insert back container exists content
                    if ($tempdoc->documentElement->childNodes->length)
                    {
                        $entries = $query->query("//*[@id='{$container}']");
                        if ($entries->length)
                        {
                            $containerDOM = $entries->item(0);
                            foreach ($tempdoc->documentElement->childNodes as $child)
                            {
                                //                                echo CHtml::encode($tempdoc->saveXML($child));
                                $existContent = $doc->importNode($child, true);
                                $containerDOM->appendChild($existContent);
                            }
                        }
                    }
                    if (is_array($result->containers) && count($result->containers))
                    {
                        $this->renderLayout($doc, $query, $result->containers);
                    }
                }
            }
            //            Yii::app()->end();
        }
    }

    protected function getAllContainer($query)
    {
        Yii::trace(__CLASS__.'.'.__FUNCTION__, __CLASS__);
        //load all containers
        $containers = array();
        $entries = $query->query("//*[@class]");
        Yii::trace('length '.CVarDumper::dumpAsString($entries->length), __CLASS__);
        if ($entries->length)
        {
            for ($i = 0; $i<$entries->length;$i++)
            {
                //echo CHtml::encode($doc->saveXML($entries->item($i)));
                $class = $entries->item($i)->attributes->getNamedItem('class')->textContent;
                Yii::trace('class '.$class, __CLASS__);
                if ($class !== null && strpos($class, 'sb-container') !== false)
                {
                    $container = $entries->item($i)->attributes->getNamedItem('id')->textContent;
                    Yii::trace('container '.$container, __CLASS__);
                    if ($container !== null)
                        array_push($containers, $container);
                }
            }
        }
        Yii::trace('containers '.CVarDumper::dumpAsString($containers), __CLASS__);
        //Yii::app()->end();
        return $containers;
    }

    /**
     * @param array $params
     *      page_id     int     page_id
     *      workflow_id int     workflow id
     * @return $url string
     */
    public function getUrl($params)
    {
        $pageId = $this->getParam($params, 'page_id', 0);
        $workflowId = $this->getParam($params, 'workflow_id', 0);
        $force = (boolean) $this->getParam($params, 'force', false);

        $url = '';
        $page = Page::model()->findByPk($pageId);
        $workflow = Workflow::model()->findByPk($workflowId);
        if (is_object($workflow) && is_object($page) && is_object($page->defaultUrl))
            $url = "http://".trim($workflow->url, "/")."/".trim($page->defaultUrl->url, "/");

        if ($force == false)
        {
            $command = Yii::app()->db->createCommand();
            $revision = $command->select('revision')
                ->from(SITE_TABLE_PREFIX.'page_current_revision')
                ->where('page_id=:page_id AND workflow_id=:workflow_id', array(
                    ':page_id'=>$pageId,
                    ':workflow_id'=>$workflowId,
                ))
                ->queryScalar();
            if (!$revision)
            {
                $url = '';
            }
        }
        else
        {
            if (strpos($url, '?') === false)
                $url .= '?';
            else
                $url .= '&';
            $url .= 'revision=1';
        }

        return $this->result->processed('url', $url);
    }
    
    public function getWidgets($params)
    {
        $pageId = $this->getParam($params,'page_id',0);
        $workflowId = $this->getParam($params,'workflow_id',0);
        $page = Page::model()->findByPk($pageId);
        $workflow = Workflow::model()->findByPk($workflowId);
        $widgets = array();
        if (is_object($page) && is_object($workflow))
        {
            $revision = FSM::run('Cms.pageRevision.getCurrent', array('page_id'=>$page->id,'workflow_url'=>$workflow->url))->revision;
            if ($revision !== false)
            {
                $criteria = array(
                    'condition'=>'revision_id=:revision_id AND status=:status', 
                    'params'=>array(':revision_id'=>$revision,':status'=>true),
                );
                
                //get widgets of current revision
                $widgets = $page->pageWidgets($criteria);
                $tmp = array();
                foreach ($widgets as $pageWidget)
                {
                    if (is_object($pageWidget->widget))
                    {
                        $type = '';
                        switch (true)
                        {
                            case stripos($pageWidget->widget->path, 'pureHtml')!==false:
                                $type = 'purehtml';
                                $content = $pageWidget->renderHtml();
                                $content = preg_replace('@<style[^>]*?>.*?</style>@siu','',$content);
                                break;
                            case stripos($pageWidget->widget->path, 'image')!==false:
                                $type = 'image';
                                $content = $pageWidget->renderHtml();
                                break;
                            case stripos($pageWidget->widget->path, 'richText')!==false:
                                $type = 'richtext';
                                $content = $pageWidget->renderHtml();
                                break;
                        }
                        if (!empty($type))
                        {
                            $tmp[] = array(
                                'id'=>$pageWidget->id,
                                'title'=>$pageWidget->widget->name,
                                'type'=>$type,
                                'content'=>$content,
                                'exported'=>(boolean) $pageWidget->exported,
                            );
                        }
                    }
                }
                $widgets = $tmp;
            }
            else
                $widgets = false;
        }
        return $this->result->processed('widgets', $widgets);
    }
}
